#include "system.h"
#include "apm32a10x.h"
#include "apm32a10x_rcm.h"
#include "apm32a10x_gpio.h"
#include "apm32a10x_usart.h"
#include "apm32a10x_tmr.h"

uint32_t SystemCoreClock = 72 * 1000 * 1000;
volatile uint32_t System_delayTick = 0;

static void SystemClockConfig(){
    __IO uint32_t i;

    RCM->CTRL_B.HSEEN = BIT_SET;

    for (i = 0; i < HSE_STARTUP_TIMEOUT; i++)
    {
        if (RCM->CTRL_B.HSERDYFLG)
        {
            break;
        }
    }

    if (RCM->CTRL_B.HSERDYFLG)
    {
        /* Enable Prefetch Buffer */
        FMC->CTRL1_B.PBEN = BIT_SET;
        /* Flash 2 wait state */
        FMC->CTRL1_B.WS = 2;

        /* HCLK = SYSCLK */
        RCM->CFG_B.AHBPSC = 0X00;
        /* PCLK2 = HCLK */
        RCM->CFG_B.APB2PSC = 0;
        /* PCLK1 = HCLK / 2 */
        RCM->CFG_B.APB1PSC = 4;

        /* PLL: HSE * 9 */
        RCM->CFG_B.PLL1SRCSEL = 1;
        RCM->CFG_B.PLL1MULCFG = 7;

        /* Enable PLL */
        RCM->CTRL_B.PLL1EN = 1;

        /* Wait PLL Ready */
        while (RCM->CTRL_B.PLL1RDYFLG == BIT_RESET);

        /* Select PLL as system clock source */
        RCM->CFG_B.SCLKSEL = 2;

        /* Wait till PLL is used as system clock source */
        while (RCM->CFG_B.SCLKSELSTS != 0x02);
    }
}


void System_setPeripheralClockEnable(PeripheralClock_t clock,BOOL_T status){
    int bus = clock / 32;
    int peripheral_index = clock % 32;
    uint32_t peripheral_bit = (0x01 << peripheral_index);
    switch ( bus ){
        case 0:
            /* AHB. */
            if ( status == TRUE ){
                RCM_EnableAHBPeriphClock(peripheral_bit);
            }else {
                RCM_DisableAHBPeriphClock(peripheral_bit);
            }
            break;
        case 1:
            /* APB1. */
            if ( status == TRUE ){
                RCM_EnableAPB1PeriphClock(peripheral_bit);
            }else {
                RCM_DisableAPB1PeriphClock(peripheral_bit);
            }
            break;
        case 2:
            /* APB2. */
            if ( status == TRUE ){
                RCM_EnableAPB2PeriphClock(peripheral_bit);
            }else {
                RCM_DisableAPB2PeriphClock(peripheral_bit);
            }
            break;
    }
}

/* System delay init. */
void System_delayInit(void){
    System_delayTick = 0;
}

void System_delayUs(int nus){
    SysTick_Config(SystemCoreClock / 100000);
    System_delayTick = nus;
    while ( System_delayTick != 0 );
}

void System_delayMs(int nms){
    SysTick_Config(SystemCoreClock / 1000);
    System_delayTick = nms;
    while ( System_delayTick != 0 );
}

void System_printInit(void){
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOA);
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_USART1);

    GPIO_Config_T gpio_configuration;
    gpio_configuration.pin = GPIO_PIN_9;
    gpio_configuration.mode = GPIO_MODE_AF_PP;
    gpio_configuration.speed = GPIO_SPEED_50MHz;
    GPIO_Config(GPIOA,&gpio_configuration);
    gpio_configuration.pin = GPIO_PIN_10;
    gpio_configuration.mode = GPIO_MODE_IN_FLOATING;
    GPIO_Config(GPIOA,&gpio_configuration);

    USART_Config_T usart_configuration;
    usart_configuration.baudRate = 115200;
    usart_configuration.wordLength = USART_WORD_LEN_8B;
    usart_configuration.parity = USART_PARITY_NONE;
    usart_configuration.stopBits = USART_STOP_BIT_1;
    usart_configuration.hardwareFlow = USART_HARDWARE_FLOW_NONE;
    usart_configuration.mode = USART_MODE_TX_RX;
    USART_Config(USART1,&usart_configuration);
    USART_Enable(USART1);
}

void SystemInit(void){
    RCM->CTRL_B.HSIEN = BIT_SET;        /* 设置HSIEN位 */
    RCM->CFG &= (uint32_t) 0xf8ff0000;  /* 复位SCLKSEL,AHBPSC,APB1PSC,APB2PSC,ADCPSC和MCOSEL的对应位 */
    RCM->CTRL &= (uint32_t) 0xfef6ffff; /* 复位HSEEN,CSSEN和PLLEN的相应位 */
    RCM->CTRL_B.HSEBCFG = BIT_RESET;    /* 复位HSEBCFG位 */
    RCM->CFG &= (uint32_t)0xff80ffff;   /* 复位PLLSRCSEL,PLLHSEPSC,PLLMULCFG和USBDIV的对应位 */
    RCM->INT = 0x009f0000;              /* 失能所有中断和清零待定标志位 */
    
    System_delayTick = 0;

    SystemClockConfig();                /* 系统时钟配置 */
    System_delayInit();
    System_printInit();
}

void _close(){
    return;
}

void _lseek(){
    return;
}

void _read(){
    return;
}

int _write(int fd,char *ptr,int len){
    int n = 0;
    for ( n = 0; n < len; n++ ){
        while ( USART_ReadStatusFlag(USART1,USART_FLAG_TXBE) == RESET );
        USART_TxData(USART1,ptr[n]);
    }
    return len;
}


__attribute__((interrupt()))
void SysTick_Handler(void){
    System_delayTick -= 1;
}

__attribute__((interrupt()))
void WWDT_IRQHandler(void){
    while ( 1 );
}

__attribute__((interrupt()))
void HardFault_Handler(void){
    while ( 1 );
}

__attribute__((interrupt()))
void BusFault_Handler(void){
    while ( 1 );
}

__attribute__((interrupt()))
void UsageFault_Handler(void){
    printf("Usage Fault\r\n");
    while ( 1 );
}

void Default_Handler(void){
    while ( 1 );
}